﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using Noris.Tools.TraceVisualiser.Components;
using Noris.Tools.TraceVisualiser.TraceData;
using Noris.Tools.TraceVisualiser.Forms;
using Noris.Tools.TraceVisualiser.Support;

namespace Noris.Tools.TraceVisualiser.Interface
{
    // Poskytovatel kontextové funkce (nad konkrétní položkou grafu):
    #region interface IFunctionContextMenuItem : předpis pro položku kontextového menu, které se nabízí na elementu grafu
    /// <summary>
    /// Interface, který předepisuje vlastnosti programu, který vytváří položku menu, které se nabízí na elementu grafu.
    /// </summary>
    public interface IFunctionContextMenuItem : IPlugin
    {
        /// <summary>
        /// Systém se ptá poskytovatele, zda chce pro daný element nabídnout svoji funkci.
        /// Tato metoda se volá jen při prvním zobrazování menu.
        /// Poskytovatel se rozhodne podle typu grafu, typu elementu a třídy řádku a elementu.
        /// V tuto chvíli není znám konkrétní element, rozhodnutí platí pro všechny obdobné elementy grafu.
        /// Pro danou kombinaci se systém ptá jen jednou.
        /// Pro konkrétní řádek a element lze pouze řídit Enabled/Disabled položky menu, a to metodou IsMenuItemEnabledFor().
        /// Pro aktivaci používání metody IsMenuItemEnabledFor() je třeba zde nastavit args.EnabledStateDependingOnElement = true;.
        /// </summary>
        /// <param name="args">Specifikace situace, která nastala, a pro kterou systém hledá nabídku funkcí. 
        /// Do tohoto argumentu by měla tato metoda vepsat popisek menu, pokud jej chce nabízet.</param>
        /// <returns></returns>
        bool IsFunctionSuitableFor(FunctionContextMenuItemSuitableArgs args);
        /// <summary>
        /// Metoda je volaná před každým zobrazením menu, a to jen pro providery kteří o to požádali.
        /// Tato žádost se vyjadřuje nastavením args.EnabledStateDependingOnElement = true; v metodě IsFunctionSuitableFor().
        /// Metoda vrací true, pokud se její menu má zobrazit jako Enabled.
        /// V tuto chvíli jsou přesně známy údaje o místě kliknutí, o konkrétním elementu i o dalších vybraných elementech.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        bool IsMenuItemEnabledFor(FunctionContextMenuItemRunArgs args);
        /// <summary>
        /// Vstupní metoda do výkonné části pluginu
        /// </summary>
        /// <param name="args"></param>
        void Run(FunctionContextMenuItemRunArgs args);
    }
    #endregion
    #region struct FunctionContextMenuItemKey : SPECIFIKACE MENU (typ grafu, typ prostoru, typ elementu, datová třída)
    /// <summary>
    /// Třída popisuje příležitost, pro kterou se hledají vhodná menu.
    /// Pokud konkrétní provider chce v dané situaci nabídnout svoje menu, pak nastaví jeho vlastnosti a vrátí true.
    /// </summary>
    public struct FunctionContextMenuItemKey
    {
        #region KONSTRUKCE
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="graphMode">Typ grafu</param>
        /// <param name="menuKind">Prostor, kde se kliklo</param>
        /// <param name="elementDrawType">Druh elementu</param>
        /// <param name="rowClassNumber">Číslo třídy řádku</param>
        /// <param name="elementClassNumber">Číslo třídy elementu</param>
        public FunctionContextMenuItemKey(RowGraphMode graphMode, FunctionContextMenuItemAreaType menuKind, GraphElementShapeType elementShapeType, int rowClassNumber, int elementClassNumber)
        {
            this._GraphMode = graphMode;
            this._AreaType = menuKind;
            this._ElementShapeType = elementShapeType;
            this._RowClassNumber = rowClassNumber;
            this._ElementClassNumber = elementClassNumber;
        }
        #endregion
        #region PROMĚNNÉ
        private RowGraphMode _GraphMode;
        private FunctionContextMenuItemAreaType _AreaType;
        private GraphElementShapeType _ElementShapeType;
        private int _RowClassNumber;
        private int _ElementClassNumber;
        #endregion
        #region OVERRIDES
        public override string ToString()
        {
            return "{RowGraph=" + this.GraphMode + "; RowClass=" + this.RowClassNumber + "; AreaType=" + this.AreaType + "; ElementDraw=" + this.ElementShapeType + "}";
        }
        public override int GetHashCode()
        {
            return this.GraphModeInt ^ this.AreaTypeInt ^ this.ElementShapeTypeInt ^ this.RowClassNumber ^ this.ElementClassNumber;
        }
        public override bool Equals(object obj)
        {
            if (obj is FunctionContextMenuItemKey)
            {
                FunctionContextMenuItemKey other = (FunctionContextMenuItemKey)obj;
                return (this._GraphMode == other._GraphMode &&
                    this._AreaType == other._AreaType &&
                    this._ElementShapeType == other._ElementShapeType &&
                    this._RowClassNumber == other._RowClassNumber &&
                    this._ElementClassNumber == other._ElementClassNumber);
            }
            return false;
        }
        private int GraphModeInt { get { return (int)this._GraphMode; } }
        private int AreaTypeInt { get { return (int)this._AreaType; } }
        private int ElementShapeTypeInt { get { return (int)this._ElementShapeType; } }
        #endregion
        #region PROPERTY
        /// <summary> { get; }
        /// Typ grafu v aktuálním řádku
        /// </summary>
        public RowGraphMode GraphMode { get { return this._GraphMode; } }
        /// <summary> { get; }
        /// Typ prostoru, kam uživatel kliknul
        /// </summary>
        public FunctionContextMenuItemAreaType AreaType { get { return this._AreaType; } }
        /// <summary> { get; }
        /// Číslo třídy řádku
        /// </summary>
        public int RowClassNumber { get { return this._RowClassNumber; } }
        /// <summary> { get; }
        /// Číslo třídy elementu
        /// </summary>
        public int ElementClassNumber { get { return this._ElementClassNumber; } }
        /// <summary> { get; }
        /// Tvar elementu.
        /// </summary>
        public GraphElementShapeType ElementShapeType { get { return this._ElementShapeType; } }
        #endregion
    }
    #endregion
    #region class FunctionContextMenuItemSuitableArgs : Třída, pomocí které se provider vyjadřuje ke konkrétní situaci, zda chce nabízet svoje menu.
    /// <summary>
    /// FunctionContextMenuItemSuitableArgs : Třída, pomocí které se provider vyjadřuje ke konkrétní situaci, zda chce nabízet svoje menu.
    /// </summary>
    public class FunctionContextMenuItemSuitableArgs
    {
        #region Konstrukce
        public FunctionContextMenuItemSuitableArgs(FunctionContextMenuItemKey menuKey)
        {
            this.MenuItems = new List<FunctionMenuItem>();
            this._MenuKey = menuKey;
        }
        private FunctionContextMenuItemKey _MenuKey;
        #endregion
        #region Property vstupní - deklarují kontext (vstupní data = co se děje)
        /// <summary> { get; }
        /// Typ grafu v aktuálním řádku
        /// </summary>
        public RowGraphMode KeyGraphMode { get { return this._MenuKey.GraphMode; } }
        /// <summary> { get; }
        /// Typ prostoru, kam uživatel kliknul
        /// </summary>
        public FunctionContextMenuItemAreaType KeyAreaType { get { return this._MenuKey.AreaType; } }
        /// <summary> { get; }
        /// Číslo třídy řádku
        /// </summary>
        public int KeyRowClassNumber { get { return this._MenuKey.RowClassNumber; } }
        /// <summary> { get; }
        /// Číslo třídy elementu
        /// </summary>
        public int KeyElementClassNumber { get { return this._MenuKey.ElementClassNumber; } }
        /// <summary> { get; }
        /// Tvar elementu.
        /// </summary>
        public GraphElementShapeType KeyElementShapeType { get { return this._MenuKey.ElementShapeType; } }
        #endregion
        #region Property výstupní - určují nabídky kontextového menu
        /// <summary>
        /// Soupis položek menu
        /// </summary>
        public List<FunctionMenuItem> MenuItems { get; private set; }
        #endregion
    }
    #endregion
    #region class FunctionContextMenuItemRunArgs : třída argumentů pro běh kontextové funkce (vstupní a výstupní data z běhu funkce).
    /// <summary>
    /// Třída argumentů pro běh kontextové funkce (vstupní a výstupní data z běhu funkce).
    /// </summary>
    public class FunctionContextMenuItemRunArgs
    {
        #region KONSTRUKCE
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="graphMode">Typ grafu</param>
        /// <param name="firstRowGId">Obsahuje GID dat, která se načetla do grafu jako základní seznam řádků.</param>
        /// <param name="tag">Tag předaný v deklaraci grafu, který volá tuto funkci.</param>
        /// <param name="menuKind">Prostor, kde se kliklo</param>
        /// <param name="elementShapeType">Druh (tvar) elementu, na který se kliknulo</param>
        /// <param name="clickedItem">Pointer na element (GID řádku a elementu)</param>
        /// <param name="dataSource">Odkaz na datový zdroj</param>
        internal FunctionContextMenuItemRunArgs(FunctionMenuItem functionItem, RowGraphMode graphMode, GID firstRowGId, object tag, TimeRange visibleTimeRange, FunctionContextMenuItemAreaType menuKind, GraphElementShapeType elementShapeType, DataPointerStr clickedItem, IDataSource dataSource)
        {
            this._FunctionItem = functionItem;
            this._GraphMode = graphMode;
            this._FirstRowGId = firstRowGId;
            this._Tag = tag;
            this._VisibleTimeRange = visibleTimeRange;
            this._AreaType = menuKind;
            this._ElementShapeType = elementShapeType;
            this._ClickedItem = clickedItem;
            this._SelectedElements = null;
            this._DataSource = dataSource;

            this.Result = new FunctionRunResults();
        }
        #endregion
        #region PROMĚNNÉ
        private FunctionMenuItem _FunctionItem;
        private RowGraphMode _GraphMode;
        private GID _FirstRowGId;
        private object _Tag;
        private TimeRange _VisibleTimeRange;
        private FunctionContextMenuItemAreaType _AreaType;
        private GraphElementShapeType _ElementShapeType;
        private DataPointerStr _ClickedItem;
        private List<DataPointerStr> _SelectedElements;
        private List<DataPointerStr> _InputElements;
        private IDataSource _DataSource;
        #endregion
        #region PROPERTY
        /// <summary> { get; }
        /// Deklarace funkce = jak ji provider funkce deklaroval. Tato deklarace se provideru zpátky předává do metody Run, pro identifikaci funkce (pokud jich jeden provider deklaruje více).
        /// </summary>
        public FunctionMenuItem FunctionItem { get { return this._FunctionItem; } internal set { this._FunctionItem = value; } }
        /// <summary> { get; }
        /// Typ grafu v aktuálním řádku
        /// </summary>
        public RowGraphMode GraphMode { get { return this._GraphMode; } }
        /// <summary>
        /// Obsahuje GID dat, která se načetla do grafu jako základní seznam řádků. Typicky určuje třídu dat v seznamu / v nejvyšší úrovni stromu.
        /// </summary>
        public GID FirstRowGId { get { return this._FirstRowGId; } }
        /// <summary>
        /// Tag předaný v deklaraci grafu, který volá tuto funkci.
        /// </summary>
        public object Tag { get { return this._Tag; } }
        /// <summary>
        /// Viditelný časový úsek v grafu
        /// </summary>
        public TimeRange VisibleTimeRange { get { return this._VisibleTimeRange; } }
        /// <summary> { get; }
        /// Typ prostoru, kam uživatel kliknul
        /// </summary>
        public FunctionContextMenuItemAreaType AreaType { get { return this._AreaType; } }
        /// <summary> { get; }
        /// Pointer na řádek a element, na kterém došlo ke kliknutí
        /// </summary>
        public DataPointerStr ClickedItem { get { return this._ClickedItem; } }
        /// <summary> { get; }
        /// Tvar elementu.
        /// </summary>
        public GraphElementShapeType ElementShapeType { get { return this._ElementShapeType; } }
        /// <summary>
        /// Datový zdroj grafu
        /// </summary>
        public IDataSource DataSource { get { return this._DataSource; } }
        /// <summary>
        /// Seznam aktuálně vybraných elementů. Nikdy není null.
        /// </summary>
        public List<DataPointerStr> SelectedElements
        {
            get
            {
                if (this._SelectedElements == null)
                    this._SelectedElements = new List<DataPointerStr>();
                return this._SelectedElements;
            }
            set { this._SelectedElements = value; this._InputElements = null; }
        }
        /// <summary>
        /// Seznam vstupních elementů: jsou to elementy selectované (označené) plus element, na který uživatel kliknul (ten je vždy první v seznamu).
        /// Pokud uživatel kliknul mimo element, a nic nevybral, je zde prázdný seznam.
        /// </summary>
        public List<DataPointerStr> InputElements
        {
            get
            {
                if (this._InputElements == null)
                {
                    DataPointerStr click = this._ClickedItem;

                    // Seznam unikátních pointerů selectovaných elementů:
                    Dictionary<DataPointerStr, object> dict = new Dictionary<DataPointerStr, object>();
                    if (this._SelectedElements != null)
                    {
                        foreach (DataPointerStr pointer in this._SelectedElements)
                        {
                            if (!pointer.IsEmpty && pointer != click && !dict.ContainsKey(pointer))
                                dict.Add(pointer, null);
                        }
                    }

                    // Výsledný soupis:
                    List<DataPointerStr> list = new List<DataPointerStr>();
                    if (!click.IsEmpty)
                        list.Add(click);
                    if (dict.Count > 0)
                        list.AddRange(dict.Keys);

                    this._InputElements = list;
                }
                return this._InputElements;
            }
        }
        /// <summary>
        /// Výsledky běhu funkce, požadavky na vizuální vrstvu
        /// </summary>
        public FunctionRunResults Result { get; private set; }
        #endregion
    }
    #endregion

    // Poskytovatel globální funkce (v menu a v toolbaru):
    #region interface IFunctionGlobalProvider : předpis pro poskytovatele globálních funkcí (zobrazují se v Menu Funkce, v Toolbaru)
    /// <summary>
    /// IFunctionGlobalProvider : předpis pro poskytovatele globálních funkcí (zobrazují se v Menu Funkce, v Toolbaru
    /// </summary>
    public interface IFunctionGlobalProvider : IPlugin
    {
        /// <summary>
        /// Metoda naplní do argumentu přehled svých funkcí, které tento poskytovatel nabízí
        /// </summary>
        /// <param name="args"></param>
        void CreateMenuItems(FunctionGlobalDeclareArgs args);
        /// <summary>
        /// Spuštění funkce
        /// </summary>
        /// <param name="args"></param>
        void Run(FunctionGlobalRunArgs args);
    }
    #endregion
    #region class FunctionGlobalRunArgs : třída argumentů pro běh globální funkce
    /// <summary>
    /// FunctionGlobalRunArgs : třída argumentů pro běh globální funkce
    /// </summary>
    public class FunctionGlobalRunArgs : FunctionRunArgs
    {
        public FunctionGlobalRunArgs(FunctionMenuItem menuItem, Form currentForm)
            : base(menuItem, currentForm)
        {
        }
    }
    #endregion

    // Poskytovatel vyhledávání v sidebaru [2013]
    #region interface ISearchProvider, IDataPersistent. Třídy argumentů SearchProviderRunArgs
    /// <summary>
    /// Předpis pro třídu, která poskytuje engine pro vyhledání dat v trace souborech.
    /// </summary>
    /// <remarks>
    /// Princip vyhledávání: v sidebaru Search se nabízí Combobox s detekovanými providery.
    /// Uživatel vybere providera (aplikace si jej pamatuje do příště).
    /// Po výběru providera se pod comboboxem zobrazí nabídka presetů + menu pro jejich správu (přednastavené parametry hledání).
    /// Pokud provider nepodporuje presety = když control vrácený metodou ISearchProvider.CreateSearchControl() nemá interface IDataPersistent, pak je combo s presety Disabled.
    /// Pod tím se zobrazí control obsahující vstupní prvky pro hledání. 
    /// Control je vytvořen providerem v metodě providera ISearchProvider.CreateSearchControl().
    /// Vrácený control by měl implementovat interface IDataPersistent, skrz který je možno vkládat / číst obsah do Xml elementu, pak je umožněna persistence presetů.
    /// Uživatel vyplní search data nebo vybere preset (a tím search data naplní), a stiskne tlačítko "Vyhledat".
    /// Okno pak předá řízení do metody ISearchProvider.Search(), v argumentech předá referenci na objekt Control (pocházející z metody ISearchProvider.CreateSearchControl()), který obsahuje aktuální data.
    /// Provider pak hledá data, nalezené údaje předává prostřednictvím argumentu zpátky, kde se v reálném čase zobrazují v okně výsledků.
    /// Provider by měl umět zareagovat na Storno hledání.
    /// </remarks>
    public interface ISearchProvider : IPlugin
    {
        /// <summary>
        /// Název providera, nabízí se v okně Search za labelem "Vyhledávač:"
        /// </summary>
        string ProviderName { get; }
        /// <summary>
        /// Metoda vytvoří a vrátí Control (typicky Panel obsahující Comboboxy, textboxy atd), které tvoří zadávací formulář pro hledání dat.
        /// Pokud provider chce, aby se data persistovala do Presetu, musí Control implementovat interface IDataPersistent.
        /// Pak okno Search bude mít zobrazený Combobox "Předvolby".
        /// Control je nezávislý na typu aktuálního dokumentu, je vytvořen po výběru providera v okně Search (první horní Combobox).
        /// </summary>
        /// <returns></returns>
        Control CreateSearchControl();
        /// <summary>
        /// Provider se připraví ke hledání dat.
        /// Dostává referenci na dokument a na objekt (Control), který obsahuje zadání pro hledání.
        /// Tento Control je identický s tím objektem, který provider sám vytvořil v metodě CreateSearchControl().
        /// V této metodě může dojít k chybě. Chyba je odchycena vně providera a ohlášena, pak se hledání nespustí.
        /// Provider může specifikovat, v kterých oblastech se má hledat (v událostech načtených v paměti: args.EnableSearchProcesses, a v dosud nenačtených trace souborech: args.EnableSearchTraceFiles).
        /// Implicitně jsou obě možnosti true.
        /// </summary>
        /// <param name="args"></param>
        void PrepareToSearch(SearchProviderPrepareArgs args);
        /// <summary>
        /// Provider zde může určit, zda jej zajímají data daného procesu (načtená v paměti).
        /// Proces je skupina událostí, definovaná readerem trace souboru. U trace aplikačního serveru je to například SessionID.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        bool CanSearchInProcess(SearchProviderDetectProcessArgs args);
        /// <summary>
        /// Provider zde může určit, zda jej zajímají data daného trace souboru (dosud nenačtený).
        /// U souboru je již určeno, o jaký soubor jde a kdo (který reader) jej bude načítat.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        bool CanSearchInTraceFile(SearchProviderDetectTraceArgs args);
        /// <summary>
        /// Provider zjistí, zda událost popisovaná v args.EventItem vyhovuje podmínkám vyhledání.
        /// Tato metoda je volána pro události již načtené v paměti.
        /// Pokud ano, vrátí true. Pro událost bude vytvořen řádek v seznamu výsledků, informace o události jsou systému známy.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        bool TestEvent(SearchProviderTestEventArgs args);
        /// <summary>
        /// Provider zjistí, zda událost popisovaná v args.Data vyhovuje podmínkám vyhledání.
        /// Tato metoda je volána pro události načtené ze souboru (v závislosti na konkrétním TraceReaderu).
        /// Pokud ano, vrátí objekt ITextGraphPointer = pointer na místo v grafu + textové popisky.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        ITextGraphPointer TestObject(SearchProviderTestTraceDataArgs args);
    }
    /// <summary>
    /// Volitelné rozhraní pro searchery, které se chtějí podílet na funkci "Vyhledej podobné události".
    /// </summary>
    public interface ISearchPatternProvider
    {
        /// <summary>
        /// Metoda zjistí, zda tento provider může být aktivován funkcí "Hledej podobné události".
        /// Provider se podívá, kterou událost uživatel vybral (kliknul na ní), a určí zda je schopen podle události naplnit svůj control.
        /// Pokud ne, vrací hodnotu 0 (nebo záporné).
        /// Pokud ano, rozhodne se, s jakou prioritou se k události postaví = vrátí číslo vyjadřující jeho vhodnost.
        /// Čím nižší číslo, tím vhodnější je tento provider.
        /// Implicitní searchery pro "svoje" události vracejí hodnoty 100-199.
        /// Expertní searchery by měly vracet hodnoty 10-99.
        /// Uživatelské searchery pak hodnoty 1-9.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        float CanSearchByPattern(SearchProviderPatternArgs args);
        /// <summary>
        /// Provider vytvoří data (XElement), která odpovídají události předané v argumentu (args.EventInfo) = element v grafu.
        /// Tato metoda se volá v průběhu výkonu funkce "Hledej podobné události", 
        /// poté kdy tento provider "vyhrál" v soutěži o nejvhodnějšího providera 
        /// (v metodě ISearchPatternProvider.CanSearchByPattern() vrátil nejnižší hodnotu větší než 0).
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        XElement CreatePresetData(SearchProviderPatternArgs args);
    }
    /// <summary>
    /// Předpis pro objekt, který dokáže akceptovat (set) nebo vygenerovat (get) svoje data do XElement objektu, odkud jsou persistována do úložiště.
    /// Nabízí property PersistentData (get; set;), skrze kterou data vstupují a vystupují.
    /// </summary>
    public interface IDataPersistent
    {
        /// <summary>
        /// Ukládaná data (get = sestaví data z hostitele do XElementu, set = převezme data z XElementu do hostitele)
        /// </summary>
        System.Xml.Linq.XElement PersistentData { get; set; }
    }
    /// <summary>
    /// Bázová třída argumentů pro interface ISearchProvider
    /// </summary>
    public class SearchProviderArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="document"></param>
        /// <param name="searchControl"></param>
        public SearchProviderArgs(TraceData.TraceDocument document, Control searchControl)
        {
            this.Document = document;
            this.SearchControl = searchControl;
        }
        /// <summary>
        /// Přístup k datům dokumentu this.Document
        /// </summary>
        public TraceData.MainInfo Main { get { return this.Document.DataSource.Main; } }
        /// <summary>
        /// Data dokumentu
        /// </summary>
        public TraceData.TraceDocument Document { get; set; }
        /// <summary>
        /// Reference na objekt, v němž jsou uloženy jednotlivé Controly se zadáním parametrů hledání.
        /// Tento Control byl vytvořen providerem hledání v jeho metodě ISearchProvider.CreateSearchControl().
        /// </summary>
        public Control SearchControl { get; private set; }
    }
    /// <summary>
    /// Třída argumentů pro interface ISearchPatternProvider.
    /// Tento interface se podílí na funkci "Najdi podobné události".
    /// </summary>
    public class SearchProviderPatternArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="eventInfo"></param>
        public SearchProviderPatternArgs(EventInfo eventInfo)
        {
            this.EventInfo = eventInfo;
        }
        /// <summary>
        /// Událost, na které uživatel vyvolal kontextovou funkci "Najdi podobné události".
        /// </summary>
        public EventInfo EventInfo { get; private set; }
    }
    /// <summary>
    /// Třída argumentů pro metodu ISearchProvider.PrepareToSearch() = příprava provideru před hledáním.
    /// Provider si převezme data zadaná do Controlu (=parametry hledání), 
    /// a naplní property argumentu EnableSearch*, kterými vyjadřuje obecný úmysl o hledání v paměti a v trace souborech.
    /// </summary>
    public class SearchProviderPrepareArgs : SearchProviderArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="document"></param>
        /// <param name="searchControl"></param>
        public SearchProviderPrepareArgs(TraceData.TraceDocument document, Control searchControl)
            : base(document, searchControl)
        {
            this.EnableSearchProcesses = true;
            this.EnableSearchTraceFiles = SearchProviderScanTraceFileMode.ScanOnlyNoProcessedFiles;
        }
        /// <summary>
        /// Provider je ochoten hledat v datech načtených do paměti?
        /// </summary>
        public bool EnableSearchProcesses { get; set; }
        /// <summary>
        /// Provider je ochoten hledat v trace souborech? V kterých?
        /// </summary>
        public SearchProviderScanTraceFileMode EnableSearchTraceFiles { get; set; }
    }
    /// <summary>
    /// Data pro určení potebnosti prohledání daného procesu
    /// </summary>
    public class SearchProviderDetectProcessArgs : SearchProviderArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="document"></param>
        /// <param name="searchControl"></param>
        /// <param name="process"></param>
        public SearchProviderDetectProcessArgs(TraceData.TraceDocument document, Control searchControl, TraceData.ProcessInfo process)
            : base(document, searchControl)
        {
            this.Process = process;
        }
        /// <summary>
        /// Proces, na který se ptáme
        /// </summary>
        public TraceData.ProcessInfo Process { get; private set; }
    }
    /// <summary>
    /// Data pro určení potřebnosti prohledání daného souboru
    /// </summary>
    public class SearchProviderDetectTraceArgs : SearchProviderArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="document"></param>
        /// <param name="searchControl"></param>
        /// <param name="trace"></param>
        public SearchProviderDetectTraceArgs (TraceData.TraceDocument document, Control searchControl, TraceData.TraceInfo trace)
            : base(document, searchControl)
        {
            this.Trace = trace;
        }
        /// <summary>
        /// Soubor, na který se ptáme
        /// </summary>
        public TraceData.TraceInfo Trace { get; private set; }
    }
    /// <summary>
    /// Data pro detekci vyhledání události v paměti
    /// </summary>
    public class SearchProviderTestEventArgs : SearchProviderDetectProcessArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="document"></param>
        /// <param name="searchControl"></param>
        /// <param name="process"></param>
        /// <param name="eventInfo"></param>
        public SearchProviderTestEventArgs(TraceData.TraceDocument document, Control searchControl, TraceData.ProcessInfo process, TraceData.EventInfo eventInfo)
            : base(document, searchControl, process)
        {
            this.EventInfo = eventInfo;
        }
        /// <summary>
        /// Data o události, jak je používaná v dokumentu
        /// </summary>
        public TraceData.EventInfo EventInfo { get; private set; }
        /// <summary>
        /// Událost, jak byla vytvořena jejím readerem.
        /// </summary>
        public TraceData.IEventItem EventItem { get { return this.EventInfo.EventItem; } }
    }
    /// <summary>
    /// Data pro detekci vyhledání události v souboru
    /// </summary>
    public class SearchProviderTestTraceDataArgs : SearchProviderDetectTraceArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="document"></param>
        /// <param name="searchControl"></param>
        /// <param name="trace"></param>
        /// <param name="data"></param>
        public SearchProviderTestTraceDataArgs(TraceData.TraceDocument document, Control searchControl, TraceData.TraceInfo trace, object data)
            : base(document, searchControl, trace)
        {
            this.Data = data;
        }
        /// <summary>
        /// Položka trace souboru, jak byla vytvořena jejím readerem.
        /// </summary>
        public object Data { get; private set; }
    }
    /// <summary>
    /// Předvolba trace souborů, které chceme prohledávat (žádné / všechny / jen soubory nenačtené v paměti)
    /// </summary>
    public enum SearchProviderScanTraceFileMode
    {
        /// <summary>
        /// Neprohledávat trace soubory vůbec
        /// </summary>
        NoSearch,
        /// <summary>
        /// Prohledávat všechny trace soubory, bez ohledu na to, zda byly zpracovány
        /// </summary>
        ScanAllFiles,
        /// <summary>
        /// Prohledávat jen ty trace soubory, které dosud nebyly zpracovány
        /// </summary>
        ScanOnlyNoProcessedFiles
    }
    #endregion

    // Třídy společné pro více providerů:
    #region class FunctionGlobalDeclareArgs : třída, pomocí které může provider globálních funkcí deklarovat svoje položky menu
    /// <summary>
    /// FunctionGlobalDeclareArgs : třída, pomocí které může provider globálních funkcí deklarovat svoje položky menu.
    /// Položky se vkládají do seznamu MenuItems.
    /// </summary>
    public class FunctionGlobalDeclareArgs
    {
        public FunctionGlobalDeclareArgs()
        {
            this.MenuItems = new List<FunctionMenuItem>();
        }
        /// <summary>
        /// Soupis položek menu
        /// </summary>
        public List<FunctionMenuItem> MenuItems { get; private set; }
    }
    #endregion
    #region class FunctionRunArgs : bázová třída pro argumenty Run (global, search)
    /// <summary>
    /// FunctionRunArgs : bázová třída pro argumenty Run (global, search)
    /// </summary>
    public class FunctionRunArgs
    {
        public FunctionRunArgs(FunctionMenuItem menuItem, Form currentForm)
        {
            this.MenuItem = menuItem;
            this.CurrentForm = currentForm;
        }
        /// <summary>
        /// Položka, která deklarovala funkci která je nyní spuštěná. Deklaraci vytvořil provider funkce v metodě IFunctionGlobalMenuItem.CreateMenuItems()
        /// </summary>
        public FunctionMenuItem MenuItem { get; private set; }
        /// <summary>
        /// Aktuální formulář (ostatní lze dohledat přes Steward.MainForm, což je MDI container)
        /// </summary>
        public Form CurrentForm { get; private set; }
        #region Property odvozené od Formu (datový zdroj)
        /// <summary>
        /// Formulář existuje?
        /// </summary>
        public bool CurrentFormExists { get { return (this.CurrentForm != null); } }
        /// <summary>
        /// Formulář existuje a je typu TraceDocumentForm?
        /// </summary>
        public bool CurrentFormIsTraceData { get { return (this.CurrentFormExists && this.CurrentForm is TraceDocumentForm); } }
        /// <summary>
        /// Aktuální formulář jako TraceDocumentForm (pokud je CurrentFormIsTraceData), nebo null
        /// </summary>
        public TraceDocumentForm CurrentTraceForm { get { return (this.CurrentFormIsTraceData ? this.CurrentForm as TraceDocumentForm : null); } }
        /// <summary>
        /// Obecný datový zdroj aktuálního formuláře, nebo null
        /// </summary>
        internal IDataSource CurrentIDataSource { get { return (this.CurrentFormIsTraceData ? this.CurrentTraceForm.DataSource : null); } }
        /// <summary>
        /// Datový zdroj aktuálního formuláře = typ TraceDataSource, nebo null
        /// </summary>
        public TraceVisualiser.TraceData.TraceDataSource CurrentTraceDataSource { get { return (this.CurrentFormIsTraceData ? this.CurrentTraceForm.DataSource : null); } }
        #endregion
    }
    #endregion
    #region class FunctionMenuItem : deklarace vzhledu jedné položky funkce. Slouží jako podklad pro tvorbu vizuální reprezentace.
    /// <summary>
    /// FunctionMenuItem : deklarace vzhledu jedné položky funkce. Slouží jako podklad pro tvorbu vizuální reprezentace.
    /// </summary>
    public class FunctionMenuItem
    {
        #region Konstruktory
        public FunctionMenuItem(int menuOrder, string menuText)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
        }
        public FunctionMenuItem(int menuOrder, string menuText, bool menuEnabledByDocumentState)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.ItemEnabledByDocumentState = menuEnabledByDocumentState;
            this.ItemProperties = (menuEnabledByDocumentState ? ToolItemProperties.EnabledDependOnTrace : ToolItemProperties.None);
        }
        public FunctionMenuItem(int menuOrder, string menuText, ToolItemProperties itemProperties)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.ItemProperties = itemProperties;
        }
        public FunctionMenuItem(int menuOrder, string menuText, string toolTipText)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.ToolTipText = toolTipText;
        }
        public FunctionMenuItem(int menuOrder, string menuText, bool menuEnabledByDocumentState, string menuToolTipText)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.ItemEnabledByDocumentState = menuEnabledByDocumentState;
            this.ItemProperties = (menuEnabledByDocumentState ? ToolItemProperties.EnabledDependOnTrace : ToolItemProperties.None);
            this.ToolTipText = menuToolTipText;
        }
        public FunctionMenuItem(int menuOrder, string menuText, ToolItemProperties itemProperties, string menuToolTipText)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.ItemProperties = itemProperties;
            this.ToolTipText = menuToolTipText;
        }
        public FunctionMenuItem(int menuOrder, string menuText, Image menuImage, Image toolbarImage)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.MenuImage = menuImage;
            this.ToolbarImage = toolbarImage;
        }
        public FunctionMenuItem(int menuOrder, string menuText, string toolTipText, Image menuImage, Image toolbarImage)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.MenuImage = menuImage;
            this.ToolbarImage = toolbarImage;
            this.ToolTipText = toolTipText;
        }
        public FunctionMenuItem(int menuOrder, string menuText, bool menuEnabledByDocumentState, Image menuImage, Image toolbarImage)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.ItemEnabledByDocumentState = menuEnabledByDocumentState;
            this.ItemProperties = (menuEnabledByDocumentState ? ToolItemProperties.EnabledDependOnTrace : ToolItemProperties.None);
            this.MenuImage = menuImage;
            this.ToolbarImage = toolbarImage;
        }
        public FunctionMenuItem(int menuOrder, string menuText, ToolItemProperties itemProperties, Image menuImage, Image toolbarImage)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.ItemProperties = itemProperties;
            this.MenuImage = menuImage;
            this.ToolbarImage = toolbarImage;
        }
        public FunctionMenuItem(int menuOrder, string menuText, string toolTipText, bool menuEnabledByDocumentState, Image menuImage, Image toolbarImage)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.ItemEnabledByDocumentState = menuEnabledByDocumentState;
            this.ItemProperties = (menuEnabledByDocumentState ? ToolItemProperties.EnabledDependOnTrace : ToolItemProperties.None);
            this.MenuImage = menuImage;
            this.ToolbarImage = toolbarImage;
            this.ToolTipText = toolTipText;
        }
        public FunctionMenuItem(int menuOrder, string menuText, string toolTipText, ToolItemProperties itemProperties, Image menuImage, Image toolbarImage)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.ItemProperties = itemProperties;
            this.MenuImage = menuImage;
            this.ToolbarImage = toolbarImage;
            this.ToolTipText = toolTipText;
        }
        public FunctionMenuItem(int menuOrder, string menuText, string toolTipText, Image menuImage, Image toolbarImage, params FunctionMenuItem[] subMenuItems)
        {
            this._SetDefaults();
            this.MenuOrder = menuOrder;
            this.MenuText = menuText;
            this.ToolTipText = toolTipText;
            this.MenuImage = menuImage;
            this.ToolbarImage = toolbarImage;
            this.SubItems = new List<FunctionMenuItem>(subMenuItems);
        }
        private void _SetDefaults()
        {
            this.ItemEnabledByDocumentState = false;
            this.ItemProperties = ToolItemProperties.None;
            this.ToolbarType = ToolItemType.None;
        }
        #endregion
        #region Property
        /// <summary> { get; set; }
        /// Klíč položky. Slouží výhradně autorovi funkce.
        /// </summary>
        public string Key { get; set; }
        /// <summary> { get; set; }
        /// Kompletně sestavená položka menu.
        /// Pokud funkce chce, může jí sestavit včetně všech parametrů, a takto bude položka zobrazována.
        /// </summary>
        public ToolStripItem MenuItem { get; set; }
        /// <summary> { get; set; }
        /// Kompletně sestavená položka toolbaru.
        /// Pokud funkce chce, může jí sestavit včetně všech parametrů, a takto bude položka zobrazována.
        /// </summary>
        public ToolStripItem ToolbarItem { get; set; }
        /// <summary> { get; set; }
        /// Typ prvku který se generuje pro Toolbar.
        /// Implicitní hodnota je None. Pro ni bude sestavena položka ToolStripMenuItem, nebo podle potřeby volajícího kódu.
        /// Pokud bude zadána explicitně, bude sestavena položka daného typu.
        /// </summary>
        public ToolItemType ToolbarType { get; set; }
        /// <summary>
        /// Vlastnosti položky menu/toolbaru
        /// </summary>
        public ToolItemProperties ItemProperties { get; set; }
        /// <summary> { get; set; }
        /// Text menu.
        /// Pokud bude null, pak se položka neobjeví v menu.
        /// </summary>
        public string MenuText { get; set; }
        /// <summary>
        /// Zkrácené klávesy v menu
        /// </summary>
        public Keys MenuShortcutKeys { get; set; }
        /// <summary> { get; set; }
        /// Obrázek v menu.
        /// Pokud bude null, pak položka nebude mít v menu obrázek.
        /// Pozor: obrázek do toolbaru se definuje v this.ToolbarImage
        /// </summary>
        public Image MenuImage { get; set; }
        /// <summary> { get; set; }
        /// Obrázek v toolbaru.
        /// Pokud bude null, pak položka nebude zobrazena v toolbaru, a to ani když bude mít obrázek v this.MenuImage (tam je obrázek pouze pro menu).
        /// </summary>
        public Image ToolbarImage { get; set; }
        /// <summary> { get; set; }
        /// Text ToolTipu
        /// </summary>
        public string ToolTipText { get; set; }
        /// <summary> { get; set; }
        /// Příznak, že položka menu může měnit svůj stav podle stavu dokumentu / elementu, na kterém je menu zavoláno.
        /// Pokud ano, pak před zobrazením menu je volána metoda GetMenuItemEnabledFor() s předáním informací o aktuálním elementu.
        /// </summary>
        public bool ItemEnabledByDocumentState { get; set; }
        /// <summary>
        /// Položky submenu (vnořené menu).
        /// Autoinstanční property (pokud dosud nebylo použito, inicializuje se na new List«FunctionMenuItem»()).
        /// Z tohoto důvodu není vhodné zjišťovat existenci submenu přes test (SubItems != null && ...), protože get zbytečně vytvoří prázdné pole.
        /// Využijte property bool ContainSubItems.
        /// </summary>
        public List<FunctionMenuItem> SubItems
        {
            get
            {
                if (_SubItems == null)
                    _SubItems = new List<FunctionMenuItem>();
                return _SubItems;
            }
            set { _SubItems = value; }
        }
        private List<FunctionMenuItem> _SubItems;
        /// <summary>
        /// Příznak, že tato položka menu obsahuje submenu
        /// </summary>
        public bool ContainSubItems
        {
            get
            {
                if (_SubItems == null) return false;
                if (_SubItems.Count == 0) return false;
                return true;
            }
        }
        /// <summary> { get; set; }
        /// Skupina menu. Pokud chceme mít svoje položky menu pohromadě, pak sem vložíme unikátní název skupiny. 
        /// Skupiny budou setříděny podle tohoto klíče skupiny, vzestupně. Klíč se nikde nezobrazuje. 
        /// Mezi položkami menu s různými klíči je vykreslen separátor.
        /// Hodnotou MenuOrder zajistíme třídění položek v rámci skupiny.
        /// </summary>
        public string MenuGroup { get; set; }
        /// <summary> { get; set; }
        /// Pořadí položky menu v rámci její skupiny MenuGroup.
        /// Výchozí hodnota je 0.
        /// Funkce může vepsat hodnotu zápornou (pak bude funkce uvedena v nabídce víc nahoře) nebo kladnou (pak bude níže).
        /// Funkce se stejnou hodnotou budou tříděny abecedně.
        /// </summary>
        public int MenuOrder { get; set; }
        /// <summary> { get; set; }
        /// Prostor pro uložení tagu. Slouží výhradně autorovi funkce.
        /// </summary>
        public object Tag { get; set; }
        /// <summary>
        /// Příznak, že MenuText není empty a položka se má dostat do menu
        /// </summary>
        public bool IsForMenu { get { return !this.MenuText.IsEmpty(); } }
        /// <summary>
        /// Příznak, že ToolbarImage není null a položka se má dostat do toolbaru
        /// </summary>
        public bool IsForToolbar { get { return this.ToolbarImage != null; } }
		/// <summary> { get; }
		/// Typ funkce = Type providera, který funkci deklaruje. Při definici se nevyplňuje, hodnotu sem vkládá jádro při aplikaci položky do systému.
		/// </summary>
		internal Type FunctionProviderType { get; set; }

        #endregion
    }
    #endregion
    #region class FunctionRunResults : výsledky běhu funkce, definují změny, které se mají provést ve vizuální vrstvě
    /// <summary>
    /// FunctionRunResults : výsledky běhu funkce, definují změny, které se mají provést ve vizuální vrstvě
    /// </summary>
    public class FunctionRunResults
    {
        public FunctionRunResults()
        {
            this.InvalidateElementsOnRows = new List<GID>();
        }
        /// <summary>
        /// Příznak, že důsledkem editace došlo ke změnám všech řádků, nebo k přidání/odebrání řádků.
        /// Pak je třeba, aby došlo k přenačtení všech řádků.
        /// </summary>
        public bool ReloadAllRows { get; set; }
        /// <summary>
        /// Příznak, že důsledkem editace došlo ke změnám všech elementů, ale není nutno načítat řádky.
        /// </summary>
        public bool InvalidateAllElements { get; set; }
        /// <summary>
        /// Obsahuje true, pokud evidujeme změněné řádky (InvalidateElementsOnRows obsahuje alespoň jednu položku).
        /// </summary>
        public bool ResultContainChangedRows { get { return (this.InvalidateElementsOnRows.Count > 0); } }
        /// <summary>
        /// Seznam řádků, jejich elementy jsou nevalidní. Je třeba je znovu načíst.
        /// Po znovunačtení obsahu řádků dojde k refreshování vizuální vrstvy = překreslení grafů.
        /// </summary>
        public List<GID> InvalidateElementsOnRows { get; set; }
        /// <summary>
        /// Seznam GIDů řádků, které se mají z grafu odebrat.
        /// Odeberou se automaticky i jejich podřízené řádky.
        /// </summary>
        public List<GID> RemoveRowList { get; set; }
        /// <summary>
        /// Seznam nově vytvořených řádků. Vizuální vrstva je přidá.
        /// Řádky se budou přidávat do Root úrovně.
        /// Pokud ale bude uveden jejich ParentGId, pak se přidají jako podřízené k danému řádku.
        /// </summary>
        public List<IDataRow> NewRowList { get; set; }
        /// <summary>
        /// Řádkový filtr, který se má aplikovat na Grid
        /// </summary>
        public RowFilter RowFilter { get; set; }
        /// <summary>
        /// Pozice, na kterou se má graf nastavit (čas, řádky, filtr)
        /// </summary>
        public IGraphPointer DocPointer { get; set; }
        /// <summary>
        /// Seznam elementů, které se mají selectovat. Pokud je null, stav selected se nezmění.
        /// </summary>
        public List<DataPointerStr> SelectElements { get; set; }
        /// <summary>
        /// Seznam elementů, které se mají vysvítit (Highlight). 
        /// Pokud jsou některé elementy Highlight, pak všechny ostatní jsou Dimmed (šedivé).
        /// Pokud je null, stav Highlight se nezmění.
        /// </summary>
        public List<DataPointerStr> HighlightElements { get; set; }
        /// <summary>
        /// Odpověď funkce, která řídí rozbalování/sbalování nodů v seznamu.
        /// Default = None.
        /// </summary>
        public GridTreeNodeActionType ResultTreeNodeAction { get; set; }
    }
    #endregion
    #region ENUM FunctionContextMenuItemAreaType : místo v grafu, kam člověk kliknul
    /// <summary>
    /// Druh objektu, na který uživatel kliknul
    /// </summary>
    public enum FunctionContextMenuItemAreaType
    {
        None = 1,
        /// <summary>
        /// Ikonka Tree:PLUS (rozbalit zabalené uzly stromu)
        /// </summary>
        TreeIconExpand,
        /// <summary>
        /// Ikonka Tree:MINUS (zabalit rozbalené uzly stromu)
        /// </summary>
        TreeIconCollapse,
        /// <summary>
        /// Prázdný řádek v grafu mezi elementy
        /// </summary>
        EmptyRow,
        /// <summary>
        /// Textová část grafu, některý sloupec
        /// </summary>
        TextItem,
        /// <summary>
        /// Záhlaví řádku (vlevo v řádku)
        /// </summary>
        RowHeader,
        /// <summary>
        /// Záhlaví sloupce (nahoře)
        /// </summary>
        ColumnHeader,
        /// <summary>
        /// Prvek grafu, element
        /// </summary>
        GraphElement
    }
    /// <summary>
    /// Požadovaná akce grafu typu Tree: rozbalit / zabalit uzly (hromadně)
    /// </summary>
    public enum GridTreeNodeActionType
    {
        /// <summary>
        /// Žádná akce
        /// </summary>
        None = 1,
        /// <summary>
        /// Rozbalit všechny nody
        /// </summary>
        ExpandAll,
        /// <summary>
        /// Zabalit všechny nody
        /// </summary>
        CollapseAll,
        /// <summary>
        /// Zabalit všechny nody kromě aktivního
        /// </summary>
        CollapseAllButThis
    }
    #endregion
}
